﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Galoap
{
    public class Statistics
    {
        private delegate int DateDelegateFunction(DateTime date);
        private delegate int UserDateDelegateFunction(User user, DateTime date);
        private delegate User ScoreDelegateFunction(DateTime date);

        /// <summary>
        /// Given an user this method returns the number of games he has ever played
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public static int GetNumberOfGamesPlayedByUser(User user)
        {
            return Game.GetAllUserGames(user).Count;
        }

        public static int GetNumberOfGamesPlayedByUser(String nickname)
        {
            return Game.GetAllUserGames(User.GetUserByNickname(nickname)).Count;
        }

        /// <summary>
        /// Given an user this method returns the number of games he has ever played
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public static int GetGameSessionsPlayedByDate(DateTime date)
        {
            return GameSession.GetGameSessionsByDate(date).Count;
        }

        public static int GetNumberOfGamesPlayedOnDate(DateTime date)
        {
            return Game.GetPlayedGamesByDate(date).Count;
        }

        public static int GetNumberOfActiveUsersOnDate(DateTime date)
        {
            return User.GetActiveUsersByDate(date).Count;
        }

        public static User GetUserWithHighestScoreByDate(DateTime date)
        {
            GameSession mySession = GameSession.GetGameSessionWithHighestScore(date);
            mySession.UserReference.Load();
            return mySession.User;
        }

        public static int GetNumberOfGameSessionsByUserOnDate(DateTime date, User user)
        {
            List<GameSession> sessions = GameSession.GetGameSessionsByDate(date);
            foreach (GameSession session in sessions) session.UserReference.Load();
            return sessions.Count(gamesession => gamesession.User.UserID == user.UserID);
        }

        public static int GetNumberOfGameSessionsByUserOnDate(DateTime date, String nickname)
        {
            return GetNumberOfGameSessionsByUserOnDate(date, User.GetUserByNickname(nickname));
        }

        public static int GetNumberOfAnswersByUserOnDate(DateTime date, User user)
        {
            int num = 0;
            foreach (GameSession gs in GameSession.GetGameSessionsByDate(date))
            {
                gs.Answer.Load();
                num += gs.Answer.Count;
            }
            return num;
        }
        public static int GetNumberOfAnswersByUserOnDate(DateTime date, String nickname)
        {
            return GetNumberOfAnswersByUserOnDate(date,User.GetUserByNickname(nickname));
        }

        public static List<int> GetGameSessionsPlayedFromToDate(User user, DateTime startDate, DateTime endDate)
        {
            return GetStatisticsFromToDate<int>(GetGameSessionsPlayedByDate, startDate, endDate);
        }

        public static List<int> GetNumberOfGamesPlayedFromToDate(User user, DateTime startDate, DateTime endDate)
        {
            return GetStatisticsFromToDate<int>(GetNumberOfGamesPlayedOnDate, startDate, endDate);
        }

        public static List<int> GetNumberOfActiveUsersFromToDate(User user, DateTime startDate, DateTime endDate)
        {
            return GetStatisticsFromToDate<int>(GetNumberOfActiveUsersOnDate, startDate, endDate);
        }

        public static List<int> GetNumberOfGameSessionsByUserFromToDate(User user, DateTime startDate, DateTime endDate)
        {
            return GetStatisticsFromToDate<User, int>(GetNumberOfGameSessionsByUserOnDate, user, startDate, endDate);
        }

        public static List<int> GetNumberOfAnswersByUserFromToDate(User user, DateTime startDate, DateTime endDate)
        {
            return GetStatisticsFromToDate<User, int>(GetNumberOfAnswersByUserOnDate, user, startDate, endDate);
        }

        public static List<User> GetUsersWithHighestScoreFromToDate(DateTime startDate, DateTime endDate)
        {
            return GetStatisticsFromToDate<User>(GetUserWithHighestScoreByDate, startDate, endDate);
        }

        public static List<T> GetStatisticsFromToDate<T>(Func<DateTime,T> method, DateTime startDate, DateTime endDate)
        {
            List<T> list = new List<T>();
            while (startDate <= endDate)
            {
                list.Add(method(startDate));
                startDate = startDate.AddDays(1);
            }
            return list;
        }

        public static List<T> GetStatisticsFromToDate<U, T>(Func<DateTime, U, T> method, U argument, DateTime startDate, DateTime endDate)
        {
            List<T> list = new List<T>();
            while (startDate <= endDate)
            {
                list.Add(method(startDate, argument));
                startDate = startDate.AddDays(1);
            }
            return list;
        }
    }
}
